﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using Moria.Common.Enum;

using Redbrick.Silverlight.Common;
using Moria;
using Redbrick.Silverlight;
using Moria.Common.Model;

namespace Moria.Silverlight.Controls
{
    public partial class NewGameDialog : ChildWindow
    {
        #region Consts & Settings


        #endregion Consts & Settings

        #region Declarations

        List<int> _origStats = new List<int>();
        BackgroundFactory _bgFactory = new BackgroundFactory();

        public static readonly DependencyProperty SocialClassProperty = DependencyProperty.Register("SocialClass", typeof(int), typeof(NewGameDialog), new PropertyMetadata(0));
        public static readonly DependencyProperty ToHitProperty = DependencyProperty.Register("ToHit", typeof(int), typeof(NewGameDialog), new PropertyMetadata(0));
        public static readonly DependencyProperty ToDmgProperty = DependencyProperty.Register("ToDmg", typeof(int), typeof(NewGameDialog), new PropertyMetadata(0));
        public static readonly DependencyProperty ToACProperty = DependencyProperty.Register("ToAC", typeof(int), typeof(NewGameDialog), new PropertyMetadata(0));
        public static readonly DependencyProperty TotalACProperty = DependencyProperty.Register("TotalAC", typeof(int), typeof(NewGameDialog), new PropertyMetadata(0));
        public static readonly DependencyProperty HistoryProperty = DependencyProperty.Register("History", typeof(string), typeof(NewGameDialog), new PropertyMetadata(string.Empty));
        public static readonly DependencyProperty StrProperty = DependencyProperty.Register("Str", typeof(string), typeof(NewGameDialog), new PropertyMetadata(string.Empty));
        public static readonly DependencyProperty IntProperty = DependencyProperty.Register("Int", typeof(string), typeof(NewGameDialog), new PropertyMetadata(string.Empty));
        public static readonly DependencyProperty WisProperty = DependencyProperty.Register("Wis", typeof(string), typeof(NewGameDialog), new PropertyMetadata(string.Empty));
        public static readonly DependencyProperty ConProperty = DependencyProperty.Register("Con", typeof(string), typeof(NewGameDialog), new PropertyMetadata(string.Empty));
        public static readonly DependencyProperty DexProperty = DependencyProperty.Register("Dex", typeof(string), typeof(NewGameDialog), new PropertyMetadata(string.Empty));
        public static readonly DependencyProperty ChrProperty = DependencyProperty.Register("Chr", typeof(string), typeof(NewGameDialog), new PropertyMetadata(string.Empty));

        #endregion Declarations

        #region Constructor

        public NewGameDialog()
        {
			  this.DebugMethodInfo();

            InitializeComponent();



            Loaded += new RoutedEventHandler(NewGameDialog_Loaded);
        }

        #endregion Constructor

        #region Methods

        private void Roll()
        {
            int[] dice = new int[18];
            int tot = 0;
            do
            {
                for (int i = 0; i < 18; i++)
                {
                    dice[i] = Dice.RandInt(3 + i % 3);  /* Roll 3,4,5 sided dice once each */
                }
                tot = dice.Sum();
            }
            while (tot.InclusiveBetween(42, 54));


            _origStats.Clear();
            for (int i = 0; i < 6; i++)
            {
                _origStats.Add(5 + dice[3 * i] + dice[3 * i + 1] + dice[3 * i + 2]);
                if (_origStats[i] < 6) _origStats[i] = 6;
            }

            if (py.Race != null)
            {
                this.GetHistory();
            }
        }

        private void AdjStats()
        {
            Race rce = py.Race;
            Class cls = py.Class;

            StatCollection modStat = new StatCollection();
            for (int i = 0; i < _origStats.Count; i++)
            {
                int n = _origStats[i];
                if (rce != null) n += rce.adj[i];
                if (cls != null) n += cls.adj[i];
                modStat[i] = n;
            }

            this.ToHit = this.tohit_adj(modStat[Stat.A_DEX], modStat[Stat.A_STR]);
            this.ToDmg = this.todam_adj(modStat[Stat.A_STR]);
            this.ToAC = this.toac_adj(modStat[Stat.A_DEX]);
            this.TotalAC = this.ToAC;




            py.ptodam = this.ToDmg;	/* Real values		*/
            py.ptohit = this.ToHit;
            py.ptoac = this.ToAC;
            py.pac = 0;
            py.dis_td = py.ptodam; /* Displayed values	*/
            py.dis_th = py.ptohit;
            py.dis_tac = py.ptoac;
            py.dis_ac = py.pac + py.dis_tac;

            /* now set misc stats, do this after setting stats because of con_adj() for hitpoints */
            //py.hitdie += cls.adj_hd;

            this.Str = modStat[Stat.A_STR].cnv_stat();
            this.Int = modStat[Stat.A_INT].cnv_stat();
            this.Wis = modStat[Stat.A_WIS].cnv_stat();
            this.Dex = modStat[Stat.A_DEX].cnv_stat();
            this.Con = modStat[Stat.A_CON].cnv_stat();
            this.Chr = modStat[Stat.A_CHR].cnv_stat();
        }

        private void GetHistory()
        {
            _bgFactory.Generate(py.prace);
            this.History = _bgFactory.History;
            this.SocialClass = _bgFactory.SocialClass;
        }

        private void GetAgeHeightWeight()
        {
            Race race = this.py.Race;
            if (race != null)
            {
                this.py.age = race.b_age + Dice.RandInt(race.m_age);
                if (this.py.isMale)
                {
                    this.py.ht = Dice.RandNor(race.m_b_ht, race.m_m_ht);
                    this.py.wt = Dice.RandNor(race.m_b_wt, race.m_m_wt);
                }
                else
                {
                    this.py.ht = Dice.RandNor(race.f_b_ht, race.f_m_ht);
                    this.py.wt = Dice.RandNor(race.f_b_wt, race.f_m_wt);
                }
            }
        }

        private int todam_adj(int str)
        {
            if (str < 4) return (-2);
            if (str < 5) return (-1);
            if (str < 16) return (0);
            if (str < 17) return (1);
            if (str < 18) return (2);
            if (str < 94) return (3);
            if (str < 109) return (4);
            if (str < 117) return (5);
            return (6);
        }
        private int toac_adj(int stat)
        {
            if (stat < 4) return (-4);
            if (stat == 4) return (-3);
            if (stat == 5) return (-2);
            if (stat == 6) return (-1);
            if (stat < 15) return (0);
            if (stat < 18) return (1);
            if (stat < 59) return (2);
            if (stat < 94) return (3);
            if (stat < 117) return (4);
            return (5);
        }
        private int tohit_adj(int dex, int str)
        {
            int total = 0;
            if (dex < 4) total = -3;
            else if (dex < 6) total = -2;
            else if (dex < 8) total = -1;
            else if (dex < 16) total = 0;
            else if (dex < 17) total = 1;
            else if (dex < 18) total = 2;
            else if (dex < 69) total = 3;
            else if (dex < 118) total = 4;
            else total = 5;

            if (str < 4) total -= 3;
            else if (str < 5) total -= 2;
            else if (str < 7) total -= 1;
            else if (str < 18) total -= 0;
            else if (str < 94) total += 1;
            else if (str < 109) total += 2;
            else if (str < 117) total += 3;
            else total += 4;
            return (total);
        }

        private bool OKCanExecute(object sender)
        {
            if (py.Race != null && py.Class != null && py.gender != Gender.Unknown && !string.IsNullOrEmpty(py.name))
                return true;
            return false;
        }

        #endregion Methods

        #region Events

        void NewGameDialog_Loaded(object sender, RoutedEventArgs e)
        {
			  this.DebugMethodInfo(sender, e);
			  if (this.DataContext == null || !(this.DataContext is Player))
            {
                throw new NullReferenceException("DataContext is null or is not of type Player");
            }

            this.OKButton.Command = new DelegateCommand(this.OKButton_Click, this.OKCanExecute);

            this.py.lev = 1;
            this.Roll();
            this.AdjStats();
            this.cbRace.ItemsSource = Race.Table;
            this.cbClass.ItemsSource = Class.Table;
            this.cbGender.ItemsSource = Enums.GetValues<Gender>().Skip(1);
        }

        private void TextBox_LostFocus(object sender, RoutedEventArgs e)
        {
            ((DelegateCommand)OKButton.Command).RaiseCanExecuteChanged();

        }

        private void OKButton_Click(object sender)
        {
			  this.DebugMethodInfo(sender);
			  for (int i = 0; i < this._origStats.Count; i++)
            {
                int stat = this._origStats[i] + this.py.Race.adj[i] + this.py.Class.adj[i];
                py.cur_stat[i] = py.max_stat[i] = stat;
                py.set_use_stat((Stat)i);
            }
            py.history = this.History;
            this.DialogResult = true;
        }

        private void RerollButton_Click(object sender, RoutedEventArgs e)
        {
            this.Roll();
            this.AdjStats();
            ((DelegateCommand)OKButton.Command).RaiseCanExecuteChanged();
        }

        private void cbRace_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (this.cbRace.SelectedIndex > -1)
            {
                this.py.prace = this.cbRace.SelectedIndex;
                this.GetHistory();
                AdjStats();
                this.GetAgeHeightWeight();
                ((DelegateCommand)OKButton.Command).RaiseCanExecuteChanged();
            }
        }

        private void cbClass_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (this.cbClass.SelectedIndex > -1)
            {
                this.py.pclass = this.cbClass.SelectedIndex;
                AdjStats();
                ((DelegateCommand)OKButton.Command).RaiseCanExecuteChanged();
            }

        }

        private void cbGender_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
             this.GetAgeHeightWeight();
             py.gender =(Gender) cbGender.SelectedValue;
           ((DelegateCommand)OKButton.Command).RaiseCanExecuteChanged();
        }

        private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
        {
            ((DelegateCommand)OKButton.Command).RaiseCanExecuteChanged();
        }

        #endregion Events

        #region Properties
        public int SocialClass
        {
            get { return (int)GetValue(SocialClassProperty); }
            set { SetValue(SocialClassProperty, value); }
        }
        public int ToDmg
        {
            get { return (int)GetValue(ToDmgProperty); }
            set { SetValue(ToDmgProperty, value); }
        }
        public int ToAC
        {
            get { return (int)GetValue(ToACProperty); }
            set { SetValue(ToACProperty, value); }
        }
        public int TotalAC
        {
            get { return (int)GetValue(TotalACProperty); }
            set { SetValue(TotalACProperty, value); }
        }
        public int ToHit
        {
            get { return (int)GetValue(ToHitProperty); }
            set { SetValue(ToHitProperty, value); }
        }
        public string Str
        {
            get { return (string)GetValue(StrProperty); }
            set { SetValue(StrProperty, value); }
        }
        public string History
        {
            get { return (string)GetValue(HistoryProperty); }
            set { SetValue(HistoryProperty, value); }
        }
        public string Int
        {
            get { return (string)GetValue(IntProperty); }
            set { SetValue(IntProperty, value); }
        }
        public string Wis
        {
            get { return (string)GetValue(WisProperty); }
            set { SetValue(WisProperty, value); }
        }
        public string Con
        {
            get { return (string)GetValue(ConProperty); }
            set { SetValue(ConProperty, value); }
        }
        public string Dex
        {
            get { return (string)GetValue(DexProperty); }
            set { SetValue(DexProperty, value); }
        }
        public string Chr
        {
            get { return (string)GetValue(ChrProperty); }
            set { SetValue(ChrProperty, value); }
        }
        Player py { get { return this.DataContext as Player; } }

        #endregion Properties

    }
}

